package proto;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import javax.swing.JOptionPane;

/**
 *
 * @author Bitjaeger
 */
public final class GeneralInput implements KeyListener, ActionListener {

    // These constants help us index the keys array
    final int KEY_L1 = 0;
    final int KEY_L2 = 1;
    final int KEY_R1 = 2;
    final int KEY_R2 = 3;
    final int KEY_U1 = 4;
    final int KEY_U2 = 5;
    final int KEY_D1 = 6;
    final int KEY_D2 = 7;
    final int KEY_CM = 8;

    @Override
    public void actionPerformed(ActionEvent e) {
        try {
            if (e.getActionCommand().equals("reset")) {
                Graphics.ClearGameArea();
                level = Loader.Load(1);
                levelNumber = 1;
                Graphics.SetLevel(level);
            } else if (e.getActionCommand().equals("restart")) {
                Graphics.ClearGameArea();
                level = Loader.Load(levelNumber);
                Graphics.SetLevel(level);
             } else if (e.getActionCommand().equals("skip")) {
                Graphics.ClearGameArea();
                if (levelNumber == 8)
                    levelNumber = 0;
                level = Loader.Load(levelNumber + 1);
                ++levelNumber;
                Graphics.SetLevel(level);
             }
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null,
                    "Failed to load level " + levelNumber, "ERROR", JOptionPane.ERROR_MESSAGE);
        }

        if (e.getActionCommand().equals("howto")) {
            Graphics.Message(
                    "Zehn kleine Jägermeister rauchten einen Joint\n" +
                    "Den einen hat es umgehaun, da waren's nur noch neun\n" +
                    "Neun kleine Jägermeister wollten gerne erben\n" +
                    "Damit es was zu erben gab, musste einer sterben\n" +
                    "Acht kleine Jägermeister fuhren gerne schnell\n" +
                    "Sieben fuhr'n nach Düsseldorf, einer fuhr nach Köln\n" +
                    "Sieben kleine Jägermeister war'n beim Rendezvous\n" +
                    "Bei einem kam ganz unverhofft der Ehemann hinzu\n" +
                    "Sechs kleine Jägermeister wollten Steuern sparen\n" +
                    "Einer wurde eingelocht, fünf durften nachbezahlen\n" +
                    "Fünf kleine Jägermeister wurden kontrolliert\n" +
                    "Ein Polizist nahm's zu genau, da war'n sie noch zu viert\n" +
                    "Vier kleine Jägermeister bei der Bundeswehr\n" +
                    "Sie tranken um die Wette, den Besten gibts nicht mehr\n" +
                    "Drei kleine Jägermeister gingen ins Lokal\n" +
                    "Dort gab's zwei Steaks mit Bohnen und eins mit Rinderwahn\n" +
                    "Zwei kleine Jägermeister baten um Asyl\n" +
                    "Einer wurde angenommen, der andere war zuviel\n" +
                    "Ein kleiner Jägermeister war nicht gern allein\n" +
                    "Drum lud er sich zum Osterfest neun neue Meister ein"
            );
        }
        else if (e.getActionCommand().equals("about")) {
            Graphics.Message("Continuity\nBitjäger csapat\nSzofver Labor 4\nWork (in hours): OVER 9000!!!");
        }
    }

    public enum Mode { STICKMAN, PUZZLE }

    /*
     * The keys array stores the states of the different keys
     * -1 = Not pressed
     * 0 = Pressed, and it should be processed now
     * >1 = Pressed, and it was processed N frames ago
     */
    private int[] keys = new int[9];
    private static Stickman[] stickmans;
    private Level level;
    private int levelNumber;
    private static Tile emptyTile;
    private static Mode mode;

    public GeneralInput() {
        for(int i = 0; i < keys.length; ++i)
            keys[i] = -1;
        try{
            level = Loader.Load(1);
            levelNumber = 1;
            Graphics.SetLevel(level);
        } catch(IOException ex){
            JOptionPane.showMessageDialog(null,
                "Failed to load level 1", "ERROR", JOptionPane.ERROR_MESSAGE);
            }
    }

    // We don't care about typed characters
    @Override
    public void keyTyped(KeyEvent e){}

    @Override
    public void keyPressed(KeyEvent e){
        // Set keys to "Pressed & Process"
        switch(e.getKeyCode()){
            case KeyEvent.VK_LEFT:
                if(keys[KEY_L1] == -1)
                    keys[KEY_L1] = 0;
                break;
            case KeyEvent.VK_RIGHT:
                if(keys[KEY_R1] == -1)
                    keys[KEY_R1] = 0;
                break;
            case KeyEvent.VK_UP:
                if(keys[KEY_U1] == -1)
                    keys[KEY_U1] = 0;
                break;
            case KeyEvent.VK_DOWN:
                if(keys[KEY_D1] == -1)
                    keys[KEY_D1] = 0;
                break;
            case KeyEvent.VK_A:
                if(keys[KEY_L2] == -1)
                    keys[KEY_L2] = 0;
                break;
            case KeyEvent.VK_D:
                if(keys[KEY_R2] == -1)
                    keys[KEY_R2] = 0;
                break;
            case KeyEvent.VK_W:
                if(keys[KEY_U2] == -1)
                    keys[KEY_U2] = 0;
                break;
            case KeyEvent.VK_S:
                if(keys[KEY_D2] == -1)
                    keys[KEY_D2] = 0;
                break;
            case KeyEvent.VK_SPACE:
                if(keys[KEY_CM] == -1)
                    keys[KEY_CM] = 0;
                break;
        }
    }

    @Override
    public void keyReleased(KeyEvent e){
        // Set keys to "Released"
        switch(e.getKeyCode()){
            case KeyEvent.VK_LEFT:  keys[KEY_L1] = -1; break;
            case KeyEvent.VK_RIGHT: keys[KEY_R1] = -1; break;
            case KeyEvent.VK_UP:    keys[KEY_U1] = -1; break;
            case KeyEvent.VK_DOWN:  keys[KEY_D1] = -1; break;
            case KeyEvent.VK_A:     keys[KEY_L2] = -1; break;
            case KeyEvent.VK_D:     keys[KEY_R2] = -1; break;
            case KeyEvent.VK_W:     keys[KEY_U2] = -1; break;
            case KeyEvent.VK_S:     keys[KEY_D2] = -1; break;
            case KeyEvent.VK_SPACE: keys[KEY_CM] = -1; break;
        }
    }

    public static void Init(Stickman[] sms, Tile emptyTil) {
        stickmans = sms;
        emptyTile = emptyTil;
        mode = Mode.STICKMAN;
    }

    public void Run(){
        final int interval = 15; // Held down keys can be processed every 15 frames (0.25 s)
        final int nopInterval = 60; // Do a nop every 60 frames (1 sec)
        int nopCounter = nopInterval; // do a nop if it reaches zero
        Graphics.DrawInfo(mode);
        while(true){
            Point[] pos = new Point[2];
            pos[0] = stickmans[0].GetPosition();
            pos[1] = stickmans[1].GetPosition();
            try{
                Thread.sleep(16); // 60 FPS -> 1/60 s = 16 ms
            }catch(InterruptedException ex){}
            //
            if(mode == Mode.STICKMAN){
                //nop
                if(nopCounter == 0){
                    boolean moved = stickmans[0].Move(Direction.DOWN);
                    stickmans[1].Move(Direction.DOWN);
                    if(!moved)
                        stickmans[0].Move(Direction.DOWN);
                    nopCounter = nopInterval;
                    Graphics.DrawInfo(mode); // Redraw
                }
                --nopCounter;
                //
                if(keys[KEY_U1] == 0)
                    stickmans[0].Move(Direction.UP);
                if(keys[KEY_L1] == 0)
                    stickmans[0].Move(Direction.LEFT);
                else if(keys[KEY_R1] == 0)
                    stickmans[0].Move(Direction.RIGHT);
                if(keys[KEY_U2] == 0)
                    stickmans[1].Move(Direction.UP);
                if(keys[KEY_L2] == 0)
                    stickmans[1].Move(Direction.LEFT);
                else if(keys[KEY_R2] == 0)
                    stickmans[1].Move(Direction.RIGHT);
            }else{
                if(keys[KEY_L1] == 0 || keys[KEY_L2] == 0)
                    emptyTile.ChangeNeighbors(Direction.RIGHT);
                else if(keys[KEY_R1] == 0 || keys[KEY_R2] == 0)
                    emptyTile.ChangeNeighbors(Direction.LEFT);
                if(keys[KEY_U1] == 0 || keys[KEY_U2] == 0)
                    emptyTile.ChangeNeighbors(Direction.DOWN);
                else if(keys[KEY_D1] == 0 || keys[KEY_D2] == 0)
                    emptyTile.ChangeNeighbors(Direction.UP);
            }
            if(keys[KEY_CM] == 0){
                ChangeMode();
                Graphics.DrawInfo(mode); // Redraw
            }
            Graphics.Draw();
            for(int i = 0; i < keys.length; ++i){
                if(keys[i] >= 0)
                    ++keys[i];
                if(keys[i] == interval)
                    keys[i] = 0; // Repeat the action
            }

            if (level.IsComplete() == true) {
                Graphics.ClearGameArea();
                // number of levels explicitly given here (8)
                if (levelNumber == 8) {
                    Graphics.Message("All levels completed!");
                    break;
                }
                Graphics.Message("Level " + levelNumber + " completed!");
                try{
                    level = Loader.Load(++levelNumber);
                    Graphics.SetLevel(level);
                } catch(IOException ex){
                    JOptionPane.showMessageDialog(null,
                    "Failed to load level " + levelNumber, "ERROR", JOptionPane.ERROR_MESSAGE);
                }
            }


        }
    }

    public void ChangeMode() {
        mode = (mode == Mode.STICKMAN) ? Mode.PUZZLE : Mode.STICKMAN;
    }
}
